package top.ffhome.common.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import top.ffhome.common.audit.AuditOperation;
import top.ffhome.common.config.BaseCurrentUser;
import top.ffhome.common.entity.BaseEntity;
import top.ffhome.common.entity.IdEntity;
import top.ffhome.common.exception.BusinessException;
import top.ffhome.common.mapper.BaseMapper;
import top.ffhome.common.page.PageRequest;
import top.ffhome.common.page.PageResult;
import top.ffhome.common.service.BaseService;
import top.ffhome.common.utils.SpringUtils;
import top.ffhome.util.reflect.ReflectUtil;
import top.ffhome.util.sql.SqlUtil;

/**
 * Service基类
 */
@Transactional(propagation = Propagation.SUPPORTS)
public class BaseServiceImpl<T extends IdEntity, Mapper extends BaseMapper<T>> implements BaseService<T> {
	protected Logger log = LoggerFactory.getLogger(getClass());
	@Autowired
	protected Mapper mapper;
	@Autowired(required = false)
	protected BaseCurrentUser currentUser;

	/**
	 * 根据ID取得对象
	 * 
	 * @param id
	 * @return
	 */
	@Override
	public T get(Long id) {
		beforeGet(id);
		T obj = mapper.get(id);
		afterGet(obj);
		return obj;
	}

	/**
	 * 取得对象前置功能
	 * 
	 * @param entity
	 */
	protected void beforeGet(Long id) {
	}

	/**
	 * 取得对象后置功能
	 * 
	 * @param entity
	 */
	protected void afterGet(T entity) {
	}

	/**
	 * 新增功能，成功增加后自动生成ID
	 * 
	 * @param entity
	 */
	@Override
	@AuditOperation(type = AuditOperation.INSERT)
	@Transactional(propagation = Propagation.REQUIRED)
	public int insert(T entity) {
		beforeInsert(entity);
		int affected = mapper.insert(entity);
		afterInsert(entity);
		return affected;
	}

	/**
	 * 新增前置功能，如需中止新增可抛出异常，自动增加创建者及时间
	 * 
	 * @param entity
	 */
	protected void beforeInsert(T entity) {
		if (entity instanceof BaseEntity) {
			BaseEntity baseEntity = (BaseEntity) entity;
			baseEntity.setCreateBy(currentUser != null ? currentUser.getId() : 0);
			baseEntity.setCreateTime(new Date());
		}
		beforeSave(entity);
	}

	/**
	 * 新增后置功能
	 * 
	 * @param entity
	 */
	protected void afterInsert(T entity) {
		afterSave(entity);
		getSelf().clearCache();
	}

	@Override
	@AuditOperation(type = AuditOperation.UPDATE)
	@Transactional(propagation = Propagation.REQUIRED)
	public int update(T entity) {
		beforeUpdate(entity);
		int affected = mapper.update(entity);
		afterUpdate(entity);
		return affected;
	}

	/**
	 * 根据修改时间，检查乐观锁
	 * 
	 * @param entity
	 */
	protected T checkOptimisticLock(T entity) {
		T quondam = null;
		if (entity instanceof BaseEntity) {
			BaseEntity baseEntity = (BaseEntity) entity;
			if (baseEntity.getUpdateTime() != null) {
				quondam = get(baseEntity.getId());
				BaseEntity original = (BaseEntity) quondam;
				if (baseEntity.getUpdateTime().compareTo(original.getUpdateTime()) != 0) {
					log.warn("保存失败!业务对象已不是最新! {} {}", baseEntity, original);
					throw new BusinessException("保存失败!业务对象已不是最新,请刷新后重新提交!");
				}
			}
			baseEntity.setUpdateBy(currentUser != null ? currentUser.getId() : 0);
			baseEntity.setUpdateTime(new Date());
		}
		return quondam;
	}

	/**
	 * 修改前置功能，如需重载此方法，需先调用父类此方法，或需单独调用检查乐观锁函数
	 * 
	 * @param entity
	 */
	protected void beforeUpdate(T entity) {
		checkOptimisticLock(entity);
		beforeSave(entity);
	}

	/**
	 * 修改后置功能
	 * 
	 * @param entity
	 */
	protected void afterUpdate(T entity) {
		afterSave(entity);
		getSelf().clearCache();
	}

	/**
	 * 保存前置功能<br/>
	 * 如果重载了preInsert，而没有调用父类方法，则新增时此方法无效<br/>
	 * 如果重载了preUpdate，而没有调用父类方法，则修改时此方法无效<br/>
	 * 
	 * @param entity
	 */
	protected void beforeSave(T entity) {
	}

	/**
	 * 保存后置功能<br/>
	 * 如果重载了afterInsert，而没有调用父类方法，则新增时此方法无效<br/>
	 * 如果重载了afterUpdate，而没有调用父类方法，则修改时此方法无效<br/>
	 * 
	 * @param entity
	 */
	protected void afterSave(T entity) {
	}

	/**
	 * 删除功能
	 * 
	 * @param ids
	 */
	@Override
	@AuditOperation(type = AuditOperation.DELETE)
	@Transactional(propagation = Propagation.REQUIRED)
	public int delete(Long id) {
		return delete(CollUtil.newArrayList(id));
	}

	/**
	 * 删除功能
	 * 
	 * @param ids
	 */
	@Override
	@AuditOperation(type = AuditOperation.DELETE)
	@Transactional(propagation = Propagation.REQUIRED)
	public int delete(List<Long> ids) {
		beforeDelete(ids);
		int affected = mapper.deleteByIds(ids);
		afterDelete(ids);
		return affected;
	}

	/**
	 * 删除前置功能
	 * 
	 * @param ids
	 */
	protected void beforeDelete(List<Long> ids) {
	}

	/**
	 * 删除后置功能
	 * 
	 * @param ids
	 */
	protected void afterDelete(List<Long> ids) {
		getSelf().clearCache();
	}

	/**
	 * 查询功能
	 * 
	 * @param dto 查询条件
	 * @return
	 */
	@Override
	public List<T> select(T dto) {
		beforeSelect(dto);
		List<T> list = mapper.select(dto);
		afterSelect(dto, list);
		return list;
	}

	@Override
	public PageResult<T> select(PageRequest request) {
		beforeSelect(request);
		if (ObjectUtil.isNotNull(request.getPageNum()) && ObjectUtil.isNotNull(request.getPageSize())) {
			String orderBy = SqlUtil.escapeOrderBySql(request.getOrderBy());
			PageHelper.startPage(request.getPageNum(), request.getPageSize(), orderBy);
		}
		T dto = ReflectUtil.newParameterizedTypeInstance(this.getClass());
		dto.setParams(request.getParams());
		List<T> list = mapper.select(dto);
		PageResult<T> page = getPageResult(request, new PageInfo<T>(list));
		afterSelect(request, page);
		return page;
	}

	private PageResult<T> getPageResult(PageRequest pageRequest, PageInfo<T> pageInfo) {
		PageResult<T> pageResult = new PageResult<T>();
		pageResult.setPageNum(pageInfo.getPageNum());
		pageResult.setPageSize(pageInfo.getPageSize());
		pageResult.setTotalSize(pageInfo.getTotal());
		pageResult.setTotalPages(pageInfo.getPages());
		pageResult.setList(pageInfo.getList());
		return pageResult;
	}

	/**
	 * 对象查询前置功能
	 * 
	 * @param entity
	 */
	protected void beforeSelect(T dto) {
		beforeSelectParam(dto.getParams());
	}

	/**
	 * 对象查询后置功能
	 * 
	 * @param entity
	 */
	protected void afterSelect(T dto, List<T> list) {
	}

	/**
	 * 分页查询前置功能
	 * 
	 * @param entity
	 */
	protected void beforeSelect(PageRequest request) {
		beforeSelectParam(request.getParams());
	}

	/**
	 * 分页查询后置功能
	 * 
	 * @param entity
	 */
	protected void afterSelect(PageRequest request, PageResult<T> page) {
	}

	/**
	 * 查询前置功能
	 * 
	 * @param entity
	 */
	protected void beforeSelectParam(Map<String, Object> params) {
	}

	public void clearCache() {
	}

	@SuppressWarnings("unchecked")
	protected BaseServiceImpl<T, Mapper> getSelf() {
		return (BaseServiceImpl<T, Mapper>) SpringUtils.getBean(this.getClass());
	}
}
